home *** CD-ROM | disk | FTP | other *** search
/ Netscape Plug-Ins Developer's Kit / Netscape_Plug-Ins_Developers_Kit.iso / CGIPERL / MACPERL / MSRCE418.HQX / Perl Source ƒ / MacPerl / MPConsole.cp < prev    next >
Encoding:
Text File  |  1994-10-27  |  10.5 KB  |  505 lines

  1. /*********************************************************************
  2. Project    :    MacPerl            -    Standalone Perl
  3. File        :    MPConsole.cp    -    Console interface for GUSI
  4. Author    :    Matthias Neeracher
  5. Language    :    MPW C/C++
  6.  
  7. $Log: MPConsole.cp,v $
  8. Revision 1.2  1994/05/04  02:49:57  neeri
  9. Safer Interrupts.
  10.  
  11. Revision 1.1  1994/02/27  23:04:58  neeri
  12. Initial revision
  13.  
  14. Revision 0.2  1993/08/30  00:00:00  neeri
  15. ShowWindow -> DoShowWindow
  16.  
  17. Revision 0.1  1993/08/14  00:00:00  neeri
  18. Remember rectangles    
  19.  
  20. *********************************************************************/
  21.  
  22. #include <GUSIFile_P.h>
  23.  
  24. #include <Resources.h>
  25. #include <Windows.h>
  26. #include <Errors.h>
  27. #include <Folders.h>
  28. #include <PLStringFuncs.h>
  29. #include <LowMem.h>
  30. #include <OSEvents.h>
  31.  
  32. #include <ioctl.h>
  33. #include <sys/types.h>
  34. #include <Signal.h>
  35.  
  36. #include "MPConsole.h"
  37.  
  38. extern "C" {
  39. #include "MPGlobals.h"
  40. #include "MPAppleEvents.h"
  41. #include "MPWindow.h"
  42. #include "MPFile.h"
  43. #include "MPMain.h"
  44. }
  45.  
  46. class MPConsoleSocket;                             // That's what this file's all about
  47.  
  48. class MPConsoleSocket : public Socket    {        
  49.     friend class MPConsoleSocketDomain;    
  50.     friend void CloseConsole(Ptr cookie);
  51.     friend void HarvestConsole(DPtr doc, MPConsoleSocket * sock);
  52.     friend int MPConsoleSpin(spin_msg msg, long arg);
  53.     
  54.                     MPConsoleSocket(DPtr window);
  55.                     
  56.     virtual         ~MPConsoleSocket();
  57.     
  58.     DPtr                    window;
  59.     Handle                input;
  60.     Boolean                nonblocking;
  61.     Boolean                eof;
  62. public:
  63.     virtual int    read(void * buffer, int buflen);
  64.     virtual int write(void * buffer, int buflen);
  65.     virtual int    fcntl(unsigned int cmd, int arg);
  66.     virtual void pre_select(Boolean wantRead, Boolean wantWrite, Boolean wantExcept);
  67.     virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
  68.     virtual void post_select(Boolean wantRead, Boolean wantWrite, Boolean wantExcept);
  69.     virtual int    ioctl(unsigned int request, void *argp);
  70.     virtual int    isatty();
  71. };    
  72.  
  73. class MPConsoleSocketDomain : public FileSocketDomain {
  74.     MPConsoleSocket *    first;
  75.     enum {
  76.         stdInput,
  77.         stdOutput,
  78.         stdError,
  79.         stdConsole,
  80.         userConsole
  81.     } consoleClass;
  82. public:
  83.     MPConsoleSocketDomain()    :    FileSocketDomain(AF_UNSPEC, true, false)    {    }
  84.     
  85.     virtual Boolean Yours(const GUSIFileRef & ref, Request request);
  86.     virtual Socket * open(const GUSIFileRef & ref, int oflag);
  87. };
  88.  
  89. MPConsoleSocketDomain    MPConsoleSockets;
  90.  
  91. #if !defined(powerc) && !defined(__powerc)
  92. #pragma segment MPConsole
  93. #endif
  94.  
  95. /************************ MPConsoleSocket members ************************/
  96.  
  97. void HarvestConsole(DPtr doc, MPConsoleSocket * sock)
  98. {                
  99.     HLock((*doc->theText)->hText);
  100.     
  101.     char * chr = *(*doc->theText)->hText + (*doc->theText)->teLength;
  102.     char * end = *(*doc->theText)->hText + doc->u.cons.fence;
  103.  
  104.     if (gGotEof == doc) {
  105.         PtrAndHand(end, sock->input, chr - end);
  106.         
  107.         doc->u.cons.fence = (*doc->theText)->teLength;
  108.         sock->eof            = true;
  109.     } else 
  110.         while (chr-- > end)
  111.             if (*chr == '\n') {
  112.                 PtrAndHand(end, sock->input, ++chr - end);
  113.                 doc->u.cons.fence = chr - *(*doc->theText)->hText;
  114.                 
  115.                 break;
  116.             }
  117.     
  118.     HUnlock((*doc->theText)->hText);
  119. }
  120.  
  121. MPConsoleSocket::MPConsoleSocket(DPtr window)
  122.     : window(window)
  123. {
  124.     nonblocking                    =    false;
  125.     eof                            =    false;
  126.     input                            =    NewHandle(0);
  127.     
  128.     if (window)
  129.         window->u.cons.cookie    =    Ptr(this);
  130. }
  131.  
  132. void CloseConsole(Ptr cookie)
  133. {
  134.     if (cookie)
  135.         ((MPConsoleSocket *) cookie)->window = nil;
  136. }
  137.  
  138. MPConsoleSocket::~MPConsoleSocket()
  139. {
  140.     DisposeHandle(input);
  141.     
  142.     if (window) {
  143.         window->u.cons.cookie    = nil;
  144.         
  145.         if (!((WindowPeek) window->theWindow)->visible)
  146.             CloseMyWindow(window->theWindow);
  147.     }
  148. }
  149.  
  150. int MPConsoleSocket::fcntl(unsigned int cmd, int arg)
  151. {
  152.     switch (cmd)    {
  153.     case F_GETFL:
  154.         if (nonblocking)
  155.             return FNDELAY;
  156.         else
  157.             return 0;
  158.     case F_SETFL:
  159.         if (arg & FNDELAY)
  160.             nonblocking = true;
  161.         else
  162.             nonblocking = false;
  163.             
  164.         return 0;
  165.     default:
  166.         return GUSI_error(EOPNOTSUPP);
  167.     }
  168. }
  169.  
  170. int MPConsoleSocket::ioctl(unsigned int request, void *argp)
  171. {
  172.     switch (request)    {
  173.     case FIONBIO:
  174.         nonblocking    =    (Boolean) *(long *) argp;
  175.         
  176.         return 0;
  177.     case FIONREAD:
  178.         *(unsigned long *) argp    = GetHandleSize(input);
  179.         
  180.         return 0;
  181.     case FIOINTERACTIVE:
  182.         return 0;
  183.     case WIOSELECT:
  184.         if (window)
  185.             SelectWindow(window->theWindow);
  186.             
  187.         return 0;
  188.     default:
  189.         return GUSI_error(EOPNOTSUPP);
  190.     }
  191. }
  192.  
  193. int MPConsoleSocket::read(void * buffer, int buflen)
  194. {
  195.     int    avail;
  196.     
  197.     avail = int(GetHandleSize(input));
  198.     
  199.     if (!avail)    {
  200.         if (eof) {
  201.             eof = false;
  202.             
  203.             return 0;
  204.         }
  205.         if (!window)
  206.             return 0;
  207.         else if (nonblocking)
  208.             return GUSI_error(EWOULDBLOCK);
  209.         else {
  210.             if (!((WindowPeek) window->theWindow)->visible)
  211.                 DoShowWindow(window->theWindow);
  212.             if (!((WindowPeek) window->theWindow)->hilited)
  213.                 SelectWindow(window->theWindow);
  214.                 
  215.             window->u.cons.selected = true;
  216.             ShowWindowStatus();
  217.             
  218.             SPIN(!(avail = int(GetHandleSize(input))) && !eof && window, SP_STREAM_READ, 0);
  219.     
  220.             if (!avail && eof)
  221.                 eof = false;
  222.                 
  223.             window->u.cons.selected = false;
  224.             ShowWindowStatus();
  225.         }
  226.     }
  227.         
  228.     buflen = min(avail, buflen);
  229.     
  230.     HLock(input);
  231.     memcpy(buffer, *input, buflen);
  232.     if (avail -= buflen)
  233.         memcpy(*input, *input+buflen, avail);
  234.     HUnlock(input);
  235.     SetHandleSize(input, avail);
  236.     
  237.     return buflen;
  238. }
  239.  
  240. int MPConsoleSocket::write(void * buffer, int buflen)
  241. {
  242.     short    oldStart;
  243.     short    oldEnd;
  244.     int    len = buflen;
  245.     
  246.     if (!window)
  247.         return GUSI_error(ESHUTDOWN);
  248.  
  249.     HarvestConsole(window, this);
  250.     
  251.     if (len > window->u.cons.memory) {
  252.         buffer = (void *) (Ptr(buffer) + len - window->u.cons.memory);
  253.         len = window->u.cons.memory;
  254.     }
  255.     
  256.     (*window->theText)->teLength += buflen;
  257.     EnforceMemory(window, window->theText);
  258.     (*window->theText)->teLength -= buflen;
  259.     
  260.     oldStart    =    (*window->theText)->selStart;
  261.     oldEnd    =    (*window->theText)->selEnd;
  262.     
  263.     if (oldStart >= window->u.cons.fence)
  264.         oldStart += buflen;
  265.     if (oldEnd >= window->u.cons.fence)
  266.         oldEnd += buflen;
  267.         
  268.     TESetSelect(window->u.cons.fence, window->u.cons.fence, window->theText);
  269.     TEInsert(buffer, buflen, window->theText);
  270.  
  271.     if (!((WindowPeek) window->theWindow)->visible) {
  272.         HideControl(window->vScrollBar);
  273.         HideControl(window->hScrollBar);
  274.         
  275.         DoShowWindow(window->theWindow);
  276.     }
  277.  
  278.     ShowSelect(window);
  279.     DrawPageExtras(window);
  280.     
  281.     TESetSelect(oldStart, oldEnd, window->theText);
  282.  
  283.     if (window->u.cons.fence < 32767)
  284.         window->u.cons.fence += buflen;
  285.     
  286.     return buflen;
  287. }
  288.  
  289. static Boolean StatusNeedsUpdate = false;
  290.  
  291. void MPConsoleSocket::pre_select(Boolean canRead, Boolean, Boolean)
  292. {
  293.     if (canRead && window) {
  294.         StatusNeedsUpdate = window->u.cons.selected = true;
  295.         
  296.         if (!((WindowPeek) window->theWindow)->visible)
  297.             DoShowWindow(window->theWindow);
  298.     }
  299. }
  300.  
  301. void MPConsoleSocket::post_select(Boolean canRead, Boolean, Boolean)
  302. {
  303.     if (canRead && window)
  304.         StatusNeedsUpdate = window->u.cons.selected = false;
  305. }
  306.  
  307. int MPConsoleSocket::select(Boolean * canRead, Boolean * canWrite, Boolean * exception)
  308. {
  309.     int        goodies     =     0;
  310.  
  311.     if (StatusNeedsUpdate) {
  312.         ShowWindowStatus();
  313.         
  314.         StatusNeedsUpdate = false;
  315.     }
  316.         
  317.     if (canRead)
  318.         if (*canRead = (GetHandleSize(input) > 0 || eof))
  319.             ++goodies;
  320.     
  321.     if (canWrite) {
  322.         *canWrite = true;
  323.         ++goodies;
  324.     }
  325.     
  326.     if (exception)
  327.         *exception = false;
  328.     
  329.     return goodies;
  330. }
  331.  
  332. int MPConsoleSocket::isatty()
  333. {
  334.     return 1;
  335. }
  336.  
  337. /********************* MPConsoleSocketDomain members **********************/
  338.  
  339. #if !defined(powerc) && !defined(__powerc)
  340. #pragma force_active on
  341. #endif
  342.  
  343. Boolean MPConsoleSocketDomain::Yours(const GUSIFileRef & ref, FileSocketDomain::Request request)
  344. {
  345.     if (ref.spec || (request != willOpen))
  346.         return false;
  347.     
  348.     switch (ref.name[4] | 0x20) {
  349.     case 's':
  350.         if (gRemoteControl)
  351.             return false;
  352.         if ((ref.name[5] | 0x20) != 't' || (ref.name[6] | 0x20) != 'd')
  353.             return false;
  354.         switch (ref.name[7] | 0x20) {
  355.         case 'i':
  356.             if ((ref.name[8] | 0x20) != 'n' || ref.name[9])
  357.                 return false;
  358.             consoleClass = stdInput;
  359.             
  360.             return true;
  361.         case 'o':
  362.             if ((ref.name[8] | 0x20) != 'u' || (ref.name[9] | 0x20) != 't' || ref.name[10])
  363.                 return false;
  364.             consoleClass = stdOutput;
  365.             
  366.             return true;
  367.         case 'e':
  368.             if ((ref.name[8] | 0x20) != 'r' || (ref.name[9] | 0x20) != 'r' || ref.name[10])
  369.                 return false;
  370.             consoleClass = stdError;
  371.             
  372.             return true;
  373.         default:
  374.             return false;
  375.         }
  376.     case 'c':
  377.         if (    (ref.name[5] | 0x20) != 'o' || (ref.name[6] | 0x20) != 'n'
  378.             || (ref.name[7] | 0x20) != 's' || (ref.name[8] | 0x20) != 'o'
  379.             || (ref.name[9] | 0x20) != 'l' || (ref.name[10] | 0x20) != 'e')
  380.             return false;
  381.         switch (ref.name[11]) {
  382.         case 0:
  383.             consoleClass = stdConsole;
  384.             
  385.             return true;
  386.         case ':':
  387.             consoleClass = userConsole;
  388.             
  389.             return true;
  390.         default:
  391.             return false;
  392.         }
  393.     default:
  394.         return false;
  395.     }
  396. }
  397.  
  398. Socket * MPConsoleSocketDomain::open(const GUSIFileRef & ref, int flags)
  399. {
  400.     DPtr                doc;
  401.     Socket *            sock = nil;
  402.     char                 title[256];
  403.     Boolean            nudoc = false;
  404.     
  405.     switch (consoleClass) {
  406.     case stdInput:
  407.         flags = O_RDONLY;
  408.         
  409.         break;
  410.     case stdOutput:
  411.         flags = O_WRONLY;
  412.         
  413.         break;
  414.     case stdError:
  415.         flags = O_WRONLY;
  416.         
  417.         break;
  418.     default:
  419.         break;
  420.     }
  421.  
  422.     if (consoleClass == userConsole) {
  423.         for (doc = gConsoleList; doc; doc = doc->u.cons.next)
  424.             if (doc->kind == kConsoleWindow) {
  425.                 getwtitle(doc->theWindow, title);
  426.                 
  427.                 if (equalstring(title, (char *) ref.name+12, false, true)) {
  428.                     if (doc->u.cons.cookie)
  429.                         sock = (Socket *) doc->u.cons.cookie;
  430.  
  431.                     goto found;
  432.                 }
  433.             }
  434.             
  435.         nudoc    = true;                
  436.         doc    = NewDocument(false, kConsoleWindow);
  437.         
  438.         setwtitle(doc->theWindow, (char *) ref.name+12);
  439.         
  440.         RestoreConsole(doc);
  441.     } else {
  442.         for (doc = gConsoleList; doc; doc = doc->u.cons.next)
  443.             if (doc->kind == kWorksheetWindow) {
  444.                 if (doc->u.cons.cookie)
  445.                     sock = (Socket *) doc->u.cons.cookie;
  446.  
  447.                 goto found;
  448.             }
  449.  
  450.         nudoc = true;
  451.         doc    = NewDocument(false, kWorksheetWindow);
  452.         SetWTitle(doc->theWindow, LMGetCurApName());
  453.  
  454.         RestoreConsole(doc);
  455.     }
  456.  
  457. found:    
  458.     if (!sock) {
  459.         errno = 0;
  460.         sock     = new MPConsoleSocket(doc);
  461.         
  462.         if (sock && errno) {
  463.             if (nudoc)
  464.                 CloseMyWindow(doc->theWindow);
  465.  
  466.             delete sock;
  467.             
  468.             return nil;
  469.         }
  470.     } else
  471.         ((MPConsoleSocket *)sock)->eof = false;
  472.  
  473.     if (!(flags & 1) && doc)
  474.         doc->u.cons.fence = (*doc->theText)->teLength;
  475.     else if (nudoc)
  476.         doc->u.cons.fence = 32767;
  477.  
  478.     return sock;
  479. }
  480.  
  481. /********************* A kinder, gentler, spin **********************/
  482.  
  483. int MPConsoleSpin(spin_msg spin, long)
  484. {
  485.     if (!gInBackground && GUSIInterrupt() && gRunningPerl) {
  486.         FlushEvents(-1, 0);
  487.  
  488.         if (spin == SP_AUTO_SPIN)
  489.             longjmp(gExitPerl, -128);
  490.         else
  491.             return -1;
  492.     }
  493.         
  494.     MainEvent(spin != SP_SELECT && spin != SP_STREAM_READ);
  495.     
  496.     for (DPtr doc = gConsoleList; doc; doc = doc->u.cons.next)
  497.         if (doc->dirty) {
  498.             if (doc->u.cons.cookie) 
  499.                 HarvestConsole(doc, (MPConsoleSocket *) doc->u.cons.cookie);
  500.             doc->dirty = false;
  501.         }
  502.     
  503.     return 0;
  504. }
  505.